package com.agent.coreservice;

import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.accessibility.AccessibleContext;
import sun.awt.AppContext;
import com.agent.diagnostic.*;

/**
 * This class handle event
 * ex: window close, window open and register window with agent core 
 *
 */

public class TAEventHandler implements WindowListener
{
	final static String CLASS_TRACE = "TAEventHandler";
	Map<String, Integer> registeredWin  = new HashMap<String, Integer>(7);
	private Map<String, Integer> mClosedMap = new HashMap<String, Integer>();
	
	private static TAEventHandler instance = null;
	
	private TAEventHandler()
	{
		
	}
	
	public void initiallize()
	{
		final String FUNCTION_TRACE = "Initiallize";
		AbtTrace.info(String.format("[%s][%s]", CLASS_TRACE, FUNCTION_TRACE));
		
		try{
			Thread t = new Thread() {
				public void run() {	
					while ( !doesHaveWindow() )		
					{
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							AbtTrace.error(String.format("[%s][%s] InterruptedException: %s",CLASS_TRACE, FUNCTION_TRACE, e.getMessage()));
						} 
					
					}
					// TODO: move register listener to control *.jar
					registerListener();
				}
			};
			t.setDaemon(true);
			t.start();
		}
		catch(Exception e)
		{
			AbtTrace.error(String.format("[%s][%s] Exception: %s", CLASS_TRACE, FUNCTION_TRACE, e.getMessage()));
		}
	}
	private static boolean  doesHaveWindow(){
		final String FUNCTION_TRACE = "DoesHaveWindow";
		boolean isHaveWindow = false;
		try{
			Vector<WeakReference<Window>> list = (Vector<WeakReference<Window>>)AppContext.getAppContext().get(Window.class);		
				
			if(list != null)
			{
				int nNumberWindow =  list.size();
				for(int i=0; i< nNumberWindow; i++ )
				{					
					try{
						WeakReference<Window> windows = list.get(i);
						Window win = windows.get();
						if(win!=null && win.isDisplayable()==true){		
							isHaveWindow = true;
							break;     
						    }
						
					}catch(Exception ex){
						AbtTrace.error(String.format("[%s][%s] Error occurred : %s", CLASS_TRACE, FUNCTION_TRACE, ex.toString()));
					}			
					
				}
			
			}
		}
		catch(Exception ex){
			AbtTrace.error(String.format("[%s][%s] Exception : %s", CLASS_TRACE, FUNCTION_TRACE, ex.getMessage()));
		}
		return isHaveWindow;
	}
	
	public static TAEventHandler getInstance()
	{
		if(TAEventHandler.instance == null)
		{
			TAEventHandler.instance = new TAEventHandler();			
		}
		return TAEventHandler.instance;
	}
	void registerListener() 
	{
		java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit ();
		AWTEventListener globalListener = new AWTEventListener () {
			public void eventDispatched (java.awt.AWTEvent e) {
				if (e instanceof WindowEvent) {
					switch (e.getID()) {
					case java.awt.event.WindowEvent.WINDOW_OPENED:
						((java.awt.event.WindowEvent) e).getWindow().addWindowListener(instance);
						break;
					default:
						break;
					}
				} 
			}
		};

		toolkit.addAWTEventListener(globalListener,java.awt.AWTEvent.WINDOW_EVENT_MASK);
		AbtTrace.info(String.format("[SwingControl][%s] End register WindowOpen listener... ", CLASS_TRACE));
		
		//try to register missing window which was opened before [SwingEventMonitor.addWindowListener(this);]
		//tryToRegisterMissingWins();
	}
	
	
//	void tryToRegisterMissingWins(){
//		AbtTrace.info(String.format("[SwingControl][%s](tryToRegisterMissingWins) Start scanning opened window... ", CLASS_TRACE));
//		try{
//		// Hau Nguyen 06/Aug/2012: change get top level window
//		//Window[] wins = EventQueueMonitor.getTopLevelWindows();
//		Window[] wins = TAEventHandler.getMyTopLevelWindows();
//			AbtTrace.info(String.format("There are %d opened window", wins.length));
//		for (Window window : wins) {
//			registerWindow(window);
//		}
//		}
//		catch(Exception e){
//			AbtTrace.warning(String.format("[SwingControl][%s](tryToRegisterMissingWins)has an exception %s... ", CLASS_TRACE,e.toString()));
//		}
//		AbtTrace.info(String.format("[SwingControl][%s](tryToRegisterMissingWins) End scanning opened window... ", CLASS_TRACE));
//		
//	}
	
	public static Window [] getMyTopLevelWindows()
	{
		
		List <Window> winList = new ArrayList<Window>();
		try{
		Vector<WeakReference<Window>> windowList =
                (Vector<WeakReference<Window>>)AppContext.getAppContext().get(Window.class);
		
		if(windowList!=null){
			for(int i=0;i<windowList.size();i++){
				Window win = windowList.get(i).get();
				if(win!=null && win.isDisplayable()==true){
					winList.add(win);
				}
			}
		}
		}
		catch(Exception ex){
			
		}
		return winList.toArray(new Window[winList.size()]);
		
	}
	
	/**
	 * 
	 */
	public void windowActivated(WindowEvent e) {
		System.out.println("==================       windowActivated(WindowEvent e)        ====================");
		Window eWin = e.getWindow();
		String winTitle = eWin.getName();
		AccessibleContext c = eWin.getAccessibleContext();
		if(c != null){
			winTitle = c.getAccessibleName();
		}		
		System.out.println("=== window title: " + winTitle);
		if(!Utilities.isContainText("Bridge.txt", winTitle)){
			System.out.println("===[huyngo]=== get free port: currently port is " + Application.getInstance().getListenerPort());
			int port = PortUtils.getFreePort(ServerConst.HARNESS_LISTENER_PORT_RANGE1, ServerConst.HARNESS_LISTENER_PORT_RANGE2);
			if(registerWindow(winTitle, port)){
				AbtTrace.info("[TAEventHandler]Register window success: " + winTitle);
			}else{
				AbtTrace.info("[TAEventHandler]Cannot register window " + winTitle);
			}
		}
	}
	
	
	/**
	 * Listen for windowOpened event and register open window to TA Register Server
	 * 	@param e Window event
	 * 
	 */
	public void windowOpened(WindowEvent e) {
		System.out.println("==================       windowOpened(WindowEvent e)        ====================");
		Window eWin = e.getWindow();
		String winTitle = eWin.getName();
		AccessibleContext c = eWin.getAccessibleContext();
		if(c != null){
			winTitle = c.getAccessibleName();
		}		
		System.out.println("=== window title: " + winTitle);
		int port = Application.getInstance().getListenerPort();
		String TCPInfo = winTitle + "\t" + String.valueOf(port); 
//		if(!Utilities.isContainText("Bridge.txt", TCPInfo))
//		{
			if(registerWindow(winTitle, port)){
				AbtTrace.info("[TAEventHandler]Register window success: " + winTitle);
			}else{
				AbtTrace.info("[TAEventHandler]Cannot register window " + winTitle);
			}
//		}
	}
	
	
	/**
	 * Listen for windowClosed event and unregister the closed window to TA Register Server
	 * @param e Window event
	 */
	public void windowClosed(WindowEvent e) {
		
//		System.out.println("==================       windowClosed(WindowEvent e)        ====================");
//		Window eWin = e.getWindow();
//		String winTitle = eWin.getName();
//		AccessibleContext c = eWin.getAccessibleContext();
//		if(c != null){
//			winTitle = c.getAccessibleName();
//		}		
//		System.out.println("=== window title: " + winTitle);
//		int port = Application.getInstance().getListenerPort();
//		if(unRegisterWindow(winTitle, port)){
//			System.out.println("[TAEventHandler]Unregister window success: " + winTitle);
//		}else{
//			System.out.println("[TAEventHandler]Cannot Unregister window " + winTitle);
//		}
	}
	
	/**
	 * @param hwnd	Window handler
	 * @param port	Window port
	 * @return		TRUE/FALSE
	 */
	private boolean registerWindow(String title, final int port){
		//save TCP/IP information
		String TCPInfo = title + "\t" + String.valueOf(port); 
		Utilities.saveFile("Bridge.txt", TCPInfo, false);
		try{
			Thread t = new Thread() {
				public void run() {	
					System.out.println(" ============= Start listener success  ====== port: " + port);
					Application.getInstance().startListener(port);
					System.out.println("ok con de!!!!!");
					
				}
			};
			t.start();
		}
		catch(Exception e)
		{
		}
		return true;
	}
	/**
	 * Unregister window from TA Register Server
	 * @param winTitle		Window title
	 * @param winHashCode	Window hash code
	 * @param agentPort		Agent port
	 * @return		TRUE/FALSE
	 */
	private boolean unRegisterWindow(String title, int port){
		
		String TCPInfo = title + "\t" + String.valueOf(port);
		System.out.println("TCPInfo: "+TCPInfo);
		Utilities.deleteLine("Bridge.txt", TCPInfo);
		return true;
	}

	/**
	 * Root cause : agent try connect to register server to register window
	 * Solution : not support this case
	 * Affect area : java platform
	 * Unregister {@link Window}
	 * @param win	Window
	 * @return	TRUE/FALSE
	 */
	private boolean unRegisterWindow(Window win){
		boolean bRet = false;
		JniHandler jniHandler = new JniHandler();
		int handle = jniHandler.getHandleWindow(win);
		int winHashCode = win.hashCode();
		
		bRet = unRegisterWindow(String.valueOf(handle), winHashCode);
		return bRet;
	}
	
	/**
	 * Get the window title
	 * @param win		Window
	 * @return		Title
	 */
	public static String getWindowTitle(Window win){
		String winTitle = win.getName();
		AccessibleContext c = win.getAccessibleContext();
		if(c != null){
			winTitle = c.getAccessibleName();
		}
		if(winTitle == null) winTitle = "";
		
		return winTitle;
	}

	/* (non-Javadoc)
	 * @see java.awt.event.WindowListener#windowClosing(java.awt.event.WindowEvent)
	 */
	public void windowClosing(WindowEvent e) {
//		System.out.println("==================       windowClosing(WindowEvent e)        ====================");
//		Window eWin = e.getWindow();
//		String winTitle = eWin.getName();
//		AccessibleContext c = eWin.getAccessibleContext();
//		if(c != null){
//			winTitle = c.getAccessibleName();
//		}		
//		System.out.println("=== window title: " + winTitle);
//		int port = Application.getInstance().getListenerPort();
//		if(unRegisterWindow(winTitle, port)){
//			System.out.println("[TAEventHandler]Unregister window success: " + winTitle);
//		}else{
//			System.out.println("[TAEventHandler]Cannot Unregister window " + winTitle);
//		}
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.WindowListener#windowDeactivated(java.awt.event.WindowEvent)
	 */
	public void windowDeactivated(WindowEvent e) {
//			AbtTrace.info("JavaAgent.windowDeactivated(): " + closedHashCode + ", " + closedHandle);
	}

	/* (non-Javadoc)
	 * @see java.awt.event.WindowListener#windowDeiconified(java.awt.event.WindowEvent)
	 */
	public void windowDeiconified(WindowEvent e) {
		
		//10/1/2013 Tuan Tran
		//ANG-2770 [JAVA] App open Well does not load controls when use bring into view function after resize window then minimize
		//Java app not update UI as soon as possible when we bringtoTop by using "showWindow" in C++.
		//Solution: we catch event windowListener "windowDeiconified" to repaint and update UI window for AUT when it restore window from minimize window.
		
		AbtTrace.info(String.format("[%s][WindowDeiconified]", CLASS_TRACE));
		Window eWin = e.getWindow();		
		eWin.repaint();

		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.WindowListener#windowIconified(java.awt.event.WindowEvent)
	 */
	public void windowIconified(WindowEvent e) {
	
	}

	

	// Start the whole shebang going


	public void guiInitialized() {
		registerListener();
		
	}

}

